import cgi
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
from google.appengine.api import memcache

import os, sys, string, Cookie, sha, time, random, cgi, urllib,urllib2
import datetime, StringIO, pickle, urllib2v
import uuid, zipfile

import wsgiref.handlers
from google.appengine.api import memcache, urlfetch
from google.appengine.ext.webapp import template
from django.utils import feedgenerator, simplejson
from django.template import Context, Template
import logging


#project module storing all the db table models
from DataStore import *
from phyloxml import *
from HelpControllers import *
from APIControllers import *

#Zip a file for user download
def ZipFiles(data):
    zipstream=StringIO.StringIO()
    file = zipfile.ZipFile(file=zipstream,compression=zipfile.ZIP_DEFLATED,mode="w")
    file.writestr('tmp',data.encode("utf-8"))
    file.close()
    zipstream.seek(0)
    return zipstream.getvalue()
   
   
#Send any uploaded data that is either file or zipped file
#and it will returnd the string
def UnzipFiles(data,iszip=False):
    if iszip is False:
        if str(data.filename)[-3:]=="zip":
            data = data.file
            try:
                tmp = zipfile.ZipFile(data, 'r')
                names = []
                for fn in tmp.namelist():
                    names.append(fn)
                data = tmp.read(names[0])
            except:
                try:
                    data = open(data,'r').read()
                except:
                    return 'error'
        else:
            data = data.file.read()
        return data
    else:
        tmp = zipfile.ZipFile(data, 'r')
        names = []
        for fn in tmp.namelist():
            names.append(fn)
        data = tmp.read(names[0])
        return data

def JSONify(data):
    pass
      
def GetCurrentUser(self):
    user = users.get_current_user()

    if users.get_current_user():
        url = users.create_logout_url(self.request.uri)
        url_linktext = 'logout'
    else:
        url = users.create_login_url(self.request.uri)
        url_linktext = 'login'
    return user,url,url_linktext
    
class TreeSave(webapp.RequestHandler):
  def post(self):
    user,url,url_linktext = GetCurrentUser(self)
    
    
    k = self.request.params.get('key', None)
    if k is None:
        self.response.out.write(None)
    
    treefile = simplejson.loads(self.request.params.get('tree', None))
    
    if treefile is None:
        self.response.out.write(None)
        
    version = os.environ['CURRENT_VERSION_ID'].split('.')
    version = str(version[0])
    
    if cmp('tmp',k[:3])==0:
        k = 'perm-phylobox-'+version+"-"+k[3:]
        tmpEntry = treeStore(objId = k,
                  objBlob = ZipFiles(simplejson.dumps(treefile)),
                  userName = str(user),
                  originalAuthor = str(user),
                  version = version
                  )
        tmpEntry.put()
        
        tmpEntry = treeOwners(objId = k,
                  userName = str(user)
                  )
        tmpEntry.put()
        
    else:
        if user is not None:
            #if the user is signed in, give them ownership of the tree object
            trees = treeStore.gql("WHERE objId = :objId AND userName = :userName",
                                objId=k, userName = str(user)).fetch(1)
            
            if len(trees)==0:
                #if the user is trying to store a tree that isn't theirs, fork it as a new tree
                #but retain the name of the originalAuthor
                trees = treeStore.gql("WHERE objId = :objId",
                                    objId=k).fetch(1)
                newk = "perm-phylobox-"+version+"-"+str(uuid.uuid4())
                
                for tree in trees:
                    tmpEntry = treeStore(objId = newk,
                              objBlob = ZipFiles(simplejson.dumps(treefile)),
                              userName = str(user),
                              forkedObj = k,
                              originalAuthor = tree.originalAuthor,
                              version = version
                              )
                    tmpEntry.put()
        
                    tmpEntry = treeOwners(objId = newk,
                              userName = str(user)
                              )
                    tmpEntry.put()
                k = newk
            else:
                #if the user is the owner of the tree, update it.
                for tree in trees:
                    tree.objBlob = ZipFiles(simplejson.dumps(treefile))
                    tree.last_update_date = datetime.datetime.now()
                    tree.put()
                    
        else:
            """ Store the forked tree as Anon """
                        
            trees = treeStore.gql("WHERE objId = :objId",
                                objId=k).fetch(1)
            newk = "perm-phylobox-"+version+"-"+str(uuid.uuid4())
            for tree in trees:
                tmpEntry = treeStore(objId = newk,
                          objBlob = ZipFiles(simplejson.dumps(treefile)),
                          userName = str(user),
                          forkedObj = k,
                          originalAuthor = tree.originalAuthor,
                          version = version
                          )
                tmpEntry.put()
    
                tmpEntry = treeOwners(objId = newk,
                          userName = str(user)
                          )
                tmpEntry.put()
                k = newk
            
            #self.response.out.write('you are trying to fork a tree when not signed in')
    self.response.out.write(k)
    
class TreeEditor(webapp.RequestHandler):
  def post(self):
    user,url,url_linktext = GetCurrentUser(self)
                
    #phyloxml = open(self.request.POST.get('phyloxml'),'r').read()
    treefile = UnzipFiles(self.request.POST.get('phyloxml'))
    #set defaults
    branch_color = "FFFFFFFF"
    branch_width = 1.5
    icon = "http://geophylo.appspot.com/static_files/icons/a99.png"
    proximity = 2
    alt_grow = 15000
    title = "GeoPhyloEngine"
    
    tree = PhyloXMLtoTree(treefile,title,alt_grow=alt_grow,proximity=proximity,branch_color=branch_color,branch_width=branch_width,icon=icon)
    tree.load()
    out = ''
    output = []
    for a,b in tree.objtree.tree.items():
        if a != 0:
            output.append(b.json())
            
    treefile = str(simplejson.dumps(output).replace('\\/','/'))
    
    #self.response.out.write(treefile)
    
    k = self.request.params.get('k', None)
    
    if k is None:
        version = os.environ['CURRENT_VERSION_ID'].split('.')
        version = str(version[0])
        k = "tmp-phylobox-"+version+"-"+str(uuid.uuid4())

    tmpEntry = tmpStore(objId = k,
                     objBlob = ZipFiles(treefile))
    tmpEntry.put()
    
    
    template_values = {
            'key':k,
            'tmp':True,
            'user':user,
            'url': url,
            'url_linktext': url_linktext
            }
            
            
    path = os.path.join(os.path.dirname(__file__), 'templates/header.html')
    header = str(template.render(path, template_values))
    
    path = os.path.join(os.path.dirname(__file__), 'templates/toolMenu.html')
    toolMenu = str(template.render(path, template_values))
    
    path = os.path.join(os.path.dirname(__file__), 'templates/editorMenu.html')
    bottomMenu = str(template.render(path, template_values))
    
    template_values['header'] = header
    template_values['toolMenu'] = toolMenu
    template_values['bottomMenu'] = bottomMenu
    
    path = os.path.join(os.path.dirname(__file__), 'templates/frame.html')
    self.response.out.write(template.render(path, template_values))
    
    
  def get(self):
    user,url,url_linktext = GetCurrentUser(self)
    
    #Default params
    BRANCH_COLOR = "#ffc412"
    NODE_COLOR = "#3333FF"
    LEAF_COLOR = "#FF3333"
    
    #Default, view the Baeolophus tree from GeoPhylo
    #use POST above to allow users to upload their own files
    
    
    k = self.request.params.get('k', None)
    if k is None:
        k = 'tmp9c63a1c1-9d89-4562-97cf-b1a479e56460'
        treefile = open("examplejson",'r').read()
        tmpEntry = tmpStore(objId = k,
                         objBlob = ZipFiles(treefile))
        tmpEntry.put()
        
    tmp = False
    if cmp('tmp',k[:3])==0:
        tmp=True
    template_values = {
            'key':k,
            'tmp':tmp,
            'user':user,
            'url': url,
            'url_linktext': url_linktext
            }
            
            
    path = os.path.join(os.path.dirname(__file__), 'templates/header.html')
    header = str(template.render(path, template_values))
    
    path = os.path.join(os.path.dirname(__file__), 'templates/toolMenu.html')
    toolMenu = str(template.render(path, template_values))
    
    path = os.path.join(os.path.dirname(__file__), 'templates/editorMenu.html')
    bottomMenu = str(template.render(path, template_values))
    
    template_values['header'] = header
    template_values['toolMenu'] = toolMenu
    template_values['bottomMenu'] = bottomMenu
    
    path = os.path.join(os.path.dirname(__file__), 'templates/frame.html')
    self.response.out.write(template.render(path, template_values))
    
      
class LookUp(webapp.RequestHandler):
  def allrequests(self):
    
    k = str(self.request.params.get('k', None)).strip()
    if k is None:
        self.response.out.write('nothing here')
        
    elif k == 'perm9c63a1c1-9d89-4562-97cf-b1a479e56460':
        treefile = open('examplejson','r').read()
        callback = self.request.params.get('callback', None)
        if callback is not None:
            treefile = callback+"("+treefile+")"
        self.response.out.write(treefile)
        
    else:
        if cmp(k[:3],"tmp")==0:
            query = tmpStore.gql("WHERE objId = :objId ",
                                objId=k)
        else:
            query = treeStore.gql("WHERE objId = :objId",
                                objId=k)
            
        callback = self.request.params.get('callback', None)
        #result = db.GqlQuery(query)
        results = query.fetch(1)
        
        
        try:
            result = UnzipFiles(StringIO.StringIO(results[0].objBlob),iszip=True)
            if cmp(k[:3],"tmp")!=0:
                results[0].last_access_date = datetime.datetime.now()
                results[0].downloadCt += 1
                results[0].put()
            if callback is not None:
                result = str(callback)+"("+result+")"
                self.response.out.write(result)
            else:
                self.response.out.write(result)
        except:
            self.response.out.write('bad zip')
        
        
        
            
  def post(self):
      self.allrequests()
  def get(self):
      self.allrequests()
        
        
      
class MainPage(webapp.RequestHandler):
  def get(self): 
    user,url,url_linktext = GetCurrentUser(self)
  
    k = "tmp-phylobox-"+version+"-"+str(uuid.uuid4())
      
    template_values = {
            'key':k,
            'user':user,
            'url': url,
            'url_linktext': url_linktext
            }
            
    path = os.path.join(os.path.dirname(__file__), 'templates/homeMenu.html')
    template_values['bottomMenu'] = template.render(path, template_values)
    
    path = os.path.join(os.path.dirname(__file__), 'templates/homepage.html')
    self.response.out.write(template.render(path, template_values))
      
         
class DailyCron(webapp.RequestHandler):
  def get(self):   
    one_day_ago = datetime.datetime.now() - datetime.timedelta(days=1)
    query = "SELECT * FROM tmpStore WHERE last_access_date < '%s' " % one_day_ago
    que = db.GqlQuery(query)
    res = que.fetch(999)
    db.delete(res)

class SignOut(webapp.RequestHandler):
  def get(self):
    self.redirect(users.create_logout_url("/"))
    
class SignIn(webapp.RequestHandler):
    def get(self):
        user = users.get_current_user()
        if user:
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.out.write('Hello, ' + user.nickname())
        else:
            self.redirect(users.create_login_url(self.request.uri))
            
            
class ProjectViewer(webapp.RequestHandler):
  def get(self):
    user,url,url_linktext = GetCurrentUser(self)

    if user is None:
        self.redirect(users.create_login_url(self.request.uri))
    else:
        k = 'perm22fad56a-2e07-4eec-b6f2-a21474ed8fc1'
        
        query = treeStore.gql("WHERE userName = :userName ORDER BY last_update_date DESC",
                            userName=str(user))
        results = query.fetch(999)
        
        rows = []
        rowType = 'even'
        ct = 1
        for r in results:
            row = {}
            row['viewLink'] = "/tree/edit?k="+r.objId
            row['deleteLink'] = "/tree/delete?k="+r.objId
            if r.originalAuthor == r.userName:
                row['author'] = "<i>you</i>"
            else:
                row['author'] = r.originalAuthor
            row['last_update_date'] = datetime.datetime.date(r.last_update_date).isoformat()
            row['downloadCt'] = r.downloadCt
            row['rowType'] = rowType
            row['rowCt'] = ct
            ct+=1
            
            rows.append(row)
            
            if rowType=='even':
                rowType = 'odd'
            else:
                rowType = 'even'
        
        template_values = {
                'user':user,
                'url': url,
                'url_linktext': url_linktext,
                'rows': rows
                }
                
        path = os.path.join(os.path.dirname(__file__), 'templates/header.html')
        template_values['header'] = template.render(path, template_values)
    
        path = os.path.join(os.path.dirname(__file__), 'templates/homeMenu.html')
        template_values['homeMenu'] = template.render(path, template_values)
        
        path = os.path.join(os.path.dirname(__file__), 'templates/projects.html')
        self.response.out.write(template.render(path, template_values))
            
            
class TreeFullscreen(webapp.RequestHandler):
  def get(self):
    k = self.request.params.get('k', None)
    if k is None:
        self.redirect('/')
    else:
        template_values = {
                'key':k
                }
        path = os.path.join(os.path.dirname(__file__), 'templates/fullscreen.html')
        self.response.out.write(template.render(path, template_values))
    
    
    
application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/signin', SignIn),
                                      ('/signout', SignOut),
                                      ('/projects', ProjectViewer),
                                      ('/api', APIServices),
                                      ('/tree/edit', TreeEditor),
                                      ('/tree/fullscreen', TreeFullscreen),
                                      ('/tree/save', TreeSave),
                                      #('/tree/widget', WidgetViewer),
                                      ('/help', HelpDirectory),
                                      ('/help/blogger', BloggerHelp),
                                      ('/help/about', AboutPhylobox),
                                      ('/lookup', LookUp),
                                      ('/dailycron', DailyCron)],      
                                     debug=False)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

